package com.travel.config.redis;

import com.travel.config.factory.AsyncScheduleThreadFactory;
import com.travel.service.impl.TravelProductServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author: libin
 * Date: 2025/6/20 8:20
 * Description:
 **/
@Slf4j
public class BloomFilterRunnable implements   Runnable{
    private StringRedisTemplate redisTemplate;
    private RedissonClient redissonClient;
    private TravelProductServiceImpl itemService;

    public BloomFilterRunnable(StringRedisTemplate redisTemplate, RedissonClient redissonClient, TravelProductServiceImpl itemService) {
        this.redisTemplate = redisTemplate;
        this.redissonClient = redissonClient;
        this.itemService = itemService;
    }

    @Override
    public void run() {
        // 重建布隆的逻辑---可能高并发依然出现穿透问题。
        // 1.先删除老布隆
        // 2.获取最新的数据
        // 3.创建新布隆以及将新数据同步到新布隆中
        // 4.新布隆上线了。

        // 新思想：（等待布隆重建完成，再删除老布隆）
        // 1、先创建新布隆
        RBloomFilter<Integer> newRBloomFilter = redissonClient.getBloomFilter("albumIdBloomFilter:new");
        newRBloomFilter.tryInit(1000000l, 0.0001);
        // 2、将新数据放到新布隆
        itemService.getProductIds().forEach(id -> {
            newRBloomFilter.add(id);
        });
        newRBloomFilter.add(20000);
        // 3、删除老布隆 && 用老布隆的名字替换新布隆名字
        // 3.1 rename KEYS[3]  KEYS[1]:用 albumIdBloomFilter替换albumIdBloomFilter:new

        String script = " redis.call(\"del\",KEYS[1])" +
                "  redis.call(\"del\",KEYS[2])" +
                "  redis.call(\"rename\",KEYS[3],KEYS[1])" +
                "  redis.call(\"rename\",KEYS[4],KEYS[2]) return 0";
        List<String> asList = Arrays.asList("albumIdBloomFilter", "{albumIdBloomFilter}:config", "albumIdBloomFilter:new", "{albumIdBloomFilter:new}:config");


        Long execute = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), asList);
        if (execute == 0) {
            log.info("新布隆已经上线");
        } else {
            log.info("老布隆依然存在");
        }

        AsyncScheduleThreadFactory instance = AsyncScheduleThreadFactory.getInstance();
        instance.execute(this, 10L, TimeUnit.SECONDS); // 测试环境用
//        instance.execute(this, 10L, TimeUnit.DAYS); // 生产环境

    }
}
